#ifndef FD_LIST_H
#define FD_LIST_H
#include <stdbool.h>
#include "bstrlib.h"

typedef struct sfd_list *fd_list;

typedef struct sfd_item *fd_item;

typedef struct sfd_server *fd_server;

fd_server
fd_server_create(void);

void
fd_server_set_new_file(fd_server server);

bool
fd_server_get_new_file(fd_server server);

void
fd_server_clear_new_file(fd_server server);

void
fd_server_set_response(fd_server server, int response);

int
fd_server_get_response(fd_server server);

void
fd_server_set_port(fd_server server, int port);

int
fd_server_get_port(fd_server server);

void
fd_server_set_fd(fd_server server, int fd);

int
fd_server_get_fd(fd_server server);

void
fd_server_set_cmd(fd_server server, int cmd);

int
fd_server_get_cmd(fd_server server);

void
fd_server_receive(fd_server server);

void
fd_server_stop_receiving(fd_server server);

bool
fd_server_should_receive(fd_server server);

void
fd_server_send(fd_server server);

void
fd_server_not_send(fd_server server);

bool
fd_server_should_send(fd_server server);

void
fd_server_clear_file(fd_server server);

void
fd_server_set_file(fd_server server, bstring file);

bstring
fd_server_get_file(fd_server server);

void
fd_server_add_recv_str(fd_server server, char* string, int i);

/*
  Obtenemos lo que hemos leido del cliente hasta ahora
*/
char*
fd_server_get_recv_str(fd_server server);

void
fd_server_reset_recv_str(fd_server server);

void
fd_server_set_transferred(fd_server server, int transferred);

int
fd_server_get_transferred(fd_server server);

void
fd_server_set_metadata(fd_server server, int metadata);

int
fd_server_get_metadata(fd_server server);

int
fd_server_append_filename(fd_server server, char* filename);

char*
fd_server_get_filename_from_list(fd_server server);

void
fd_server_swap_filename(fd_server server);

void
fd_server_remove_filename_from_list(fd_server server);

void
fd_server_set_relation(fd_server server, int i);

int
fd_server_get_relation(fd_server server);

void
fd_server_set_recv(fd_server server, bool recv);

/*
  Informa el estado del fd, true == recibio el comando completo, 
  false == !recibio el comando completo
*/

bool
fd_server_get_recv(fd_server server);

int
fd_server_get_filenames_count(fd_server server);

void
fd_server_set_start_over(fd_server server);

void
fd_server_clear_start_over(fd_server server);

bool
fd_server_should_start_over(fd_server server);

void
fd_server_destroy(fd_server server);

/*
  Devuelve un item vacio
*/
fd_item
fd_item_create(void);

/*
  Permite setear el numero de fd del item
*/
void
fd_item_set_fd(fd_item item, int fd);

/*
  Obtenemos el fd
*/
int
fd_item_get_fd(fd_item item);
/*
  Permite setear el comando pedido en el fd
  0 = get_file_listing
  1 = get_metadata
  2 = get_slice
  3 = quit
*/
void
fd_item_set_cmd(fd_item item, int cmd);

/*
  Obtenemos el comando con el que esta seteado el fd
*/
int
fd_item_get_cmd(fd_item item);

/*
  Seteamos el campo Attended, para saber si un comando ya se finalizo de
  atender
*/
void
fd_item_set_atnd(fd_item item, bool atnd);

/*
  Informa sobre el estado del fd, true == atendido, false == !atentido
*/
bool
fd_item_get_atnd(fd_item item);

/*
  Seteamos el estado del fd, true == recibio el comando completo, 
  false == !recibio el comando completo
*/

void
fd_item_set_recv(fd_item item, bool recv);

/*
  Informa el estado del fd, true == recibio el comando completo, 
  false == !recibio el comando completo
*/

bool
fd_item_get_recv(fd_item item);

/*
  Cargamos el nombre del archivo,
  usado en los comando get_slice y get_metadata
*/
void
fd_item_set_filename(fd_item item, char* filename);

/*
  Obtenemos el nombre del archivo
*/
char*
fd_item_get_filename(fd_item item);

/*
  Con esta funcion vamos cargando lo que el cliente nos
  manda
*/
void
fd_item_add_recv_str(fd_item item, char* string, int i);

/*
  Obtenemos lo que hemos leido del cliente hasta ahora
*/
char*
fd_item_get_recv_str(fd_item item);

void
fd_item_reset_recv_str(fd_item item);

/*
  Seteamos el offset del archivo pedido
*/
void
fd_item_set_offset(fd_item item, int offset);

/*
  Obtenemos el offset pedido
*/
int
fd_item_get_offset(fd_item item);

/*
  Seteamos el amount pedido
*/
void
fd_item_set_amount(fd_item item, int amount);

/*
  Obetenemos el amount pedido
*/

int
fd_item_get_amount(fd_item item);

/*
  Aca vamos cargando cuanto ya le hemos enviado al cliente
*/
void
fd_item_set_transferred(fd_item item, int transferred);

/*
  Obtenemos informacion sobre cuanto hemos enviado al cliente
*/

int
fd_item_get_transferred(fd_item item);

void
fd_item_set_relation(fd_item item, int i);

int
fd_item_get_relation(fd_item item);

void
fd_item_visited(fd_item item);

bool
fd_item_is_first_time(fd_item item);

void
fd_item_set_port(fd_item item, int aux);

int
fd_item_get_port(fd_item item);

/*
  Este es el destructor
*/
void
fd_item_destroy(fd_item item);

/*
  ACA EMPIEZAN LAS FUNCIONES DE LISTA
*/

/*
  Constructor de lista
*/
fd_list
fd_list_create(void);

/*
  Aqui vamos agregando items a la lista de fd's
  le pasamos el fd, y el comando pedido, el fd es cargado
  en el ultimo lugar de la lista
*/
void
fd_list_add_fd(fd_list list, int fd);

/*
  Obtenemos el fd
*/
int
fd_list_get_fd(fd_list list, int n);

void
fd_list_add_server_fd(fd_list list, int fd);

/*
  Obtenemos el fd
*/
int
fd_list_get_server_fd(fd_list list, int n);

/*
  Seteamos el comando para el fd
*/
void
fd_list_set_cmd(fd_list list, int n, int cmd);

/*
  Obetenemos el comando con el que fue seteado el fd
*/
int
fd_list_get_cmd(fd_list list, int n);

void
fd_list_set_server_cmd(fd_list list, int n, int cmd);

/*
  Obetenemos el comando con el que fue seteado el fd
*/
int
fd_list_get_server_cmd(fd_list list, int n);

/*
  Con esta funcion sacamos el elemento n de la lista
*/
void
fd_list_remove(fd_list list, int n);

void
fd_list_server_remove(fd_list list, int n);

/*
  Con esta funcion devolvemos la ubicacion en la lista
  de un fd
*/
int
fd_list_search(fd_list list, int fd);

int
fd_list_server_search(fd_list list, int fd);

/*
  Obtenemos el item con indice n
*/
fd_item
fd_list_get_item(fd_list list, int n);

fd_server
fd_list_get_server(fd_list list, int n);

/*
  Cargamos un fd con el nombre del archivo pedido, donde comienza 
  y donde termina el pedido
*/
void
fd_list_add_file(fd_list list, int n, char* filename, int offset,\
                 int amount);

/*
  Obtenemos el nombre del archivo pedido por el fd ubicado en la posicion
  n de la lista
*/
char*
fd_list_get_filename(fd_list list, int n);

/*
  Seteamos el filename del fd ubicado en la posicion n de la lista
*/
void
fd_list_set_filename(fd_list list, int n, char* filename);


void
fd_list_server_clear_file(fd_list list, int n);

void
fd_list_server_set_file(fd_list list, int n, bstring file);

bstring
fd_list_server_get_file(fd_list list, int n);

/*
  Obtenemos lo recibido del fd ubicado en la posicion n de la lista
*/
char*
fd_list_get_recv_str(fd_list list, int n);

/*
  Seteamos el filename del fd ubicado en la posicion n de la lista
*/
void
fd_list_add_recv_str(fd_list list, int n, char* string, int i);

void
fd_list_reset_recv_str(fd_list list, int n);

char*
fd_list_get_server_recv_str(fd_list list, int n);

/*
  Seteamos el filename del fd ubicado en la posicion n de la lista
*/
void
fd_list_add_server_recv_str(fd_list list, int n, char* string, int i);

void
fd_list_reset_server_recv_str(fd_list list, int n);

/*
  Obtenemos el offset pedido en el fd ubicado en la posicion n de la lista
*/
int
fd_list_get_offset(fd_list list, int n);

/*
  Seteamos el offset en el fd ubicado en la posicion n de la lista
*/
void
fd_list_set_offset(fd_list list, int n, int m);

/*
  Obtenemos el amount del fd ubicado en la posicion n de la lista
*/
int
fd_list_get_amount(fd_list list, int n);

/*
  Seteamos el amount en el fd ubicado en la posicion n de la lista
*/
void
fd_list_set_amount(fd_list list, int n, int m);

/*
  Obtenemos el numero de fd's en la lista (tamaño de la lista)
*/
int
fd_list_size(fd_list list);

int
fd_list_server_size(fd_list list);

/*
  Seteamos el campo que informa si el fd ubicado en la posicion n de la lista,
  se finalizo de atender
*/
void
fd_list_set_finish(fd_list list, int n, bool b);

/*
  Obtenemos el campo que informa si el fd termino
*/
bool
fd_list_get_finish(fd_list list, int n);

/*
  Seteamos la cantidad transferida del archivo en el fd ubicado
  en la posicion n de la lista
*/
void
fd_list_set_transferred(fd_list list, int n, int transferred);

/*
  Obtenemos la cantidad transferida del archivo en el fd ubicado
  en la posicion n de la lista
*/
int
fd_list_get_transferred(fd_list list, int n);

/*
  Seteamos si el fd ubicado en la posicion n de la lista termino de enviarnos
  todo el comando.
*/
void
fd_list_set_recv(fd_list list, int n, bool recv);

/*
  Preguntamos si el fd ubicado en la posicion n de la lista nos ha enviado
  el comando completo.
*/
bool
fd_list_get_recv(fd_list list, int n);

void
fd_list_set_server_recv(fd_list list, int n, bool recv);

/*
  Preguntamos si el fd ubicado en la posicion n de la lista nos ha enviado
  el comando completo.
*/
bool
fd_list_get_server_recv(fd_list list, int n);

void
fd_list_server_receive(fd_list list, int n);

void
fd_list_server_send(fd_list list, int n);

void
fd_list_server_stop_receiving(fd_list list, int n);

void
fd_list_server_not_send(fd_list list, int n);

bool
fd_list_server_should_receive(fd_list list, int n);

bool
fd_list_server_should_send(fd_list list, int n);

void
fd_list_server_set_transferred(fd_list list, int n, int transferred);

int
fd_list_server_get_transferred(fd_list list, int n);

void
fd_list_server_set_metadata(fd_list list, int n, int metadata);

int
fd_list_server_get_metadata(fd_list list, int n);

void
fd_list_server_append_filename(fd_list list, int n, char* filename);

char*
fd_list_server_get_filename_from_list(fd_list list, int n);

void
fd_list_server_swap_filename(fd_list list, int n);

void
fd_list_server_remove_filename_from_list(fd_list list, int n);

void
fd_list_server_set_relation(fd_list list, int n, int i);

int
fd_list_server_get_relation(fd_list list, int n);

void
fd_list_item_set_relation(fd_list list, int n, int i);

int
fd_list_item_get_relation(fd_list list, int n);

void
fd_list_item_visited(fd_list list, int n);

bool
fd_list_is_first_time(fd_list list, int n);

void
fd_list_set_item_port(fd_list list, int n, int aux);

int
fd_list_get_item_port(fd_list list, int n);

void
fd_list_set_server_port(fd_list list, int n, int port);

int
fd_list_get_server_port(fd_list list, int n);

void
fd_list_set_server_response(fd_list list, int n, int response);

int
fd_list_get_server_response(fd_list list, int n);

int
fd_list_get_server_filenames_count(fd_list list, int n);

void
fd_list_server_clear_new_file(fd_list list);

void
fd_list_server_set_new_file(fd_list list, int i);

bool
fd_list_server_get_new_file(fd_list list, int i);

void
fd_list_server_set_start_over(fd_list list, int i);

void
fd_list_server_clear_start_over(fd_list list, int i);

bool
fd_list_server_should_start_over(fd_list list, int i);

/*
  Destructor del tipo fd_list
*/
void
fd_list_destroy(fd_list list);

#endif 
